package com.wili.extract_srcFile.java;
import java.io.File;
import java.io.Serializable;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import com.c.Ca;
import com.wili.c.Class9;
import com.wili.c.File9;
import com.wili.c.Misc9;
import _a.ExtractConf;
import _a.LogConf;
import javassist.ClassClassPath;
import javassist.NotFoundException;
/**
 * 	汇集 java源码中各个函数的起止范围及行号信息。
 * @author weila 2021年2月12日
 */
public class RangesOfClsMember implements Serializable {
	private static final long serialVersionUID = 1L;

	/**
	 *  main|first class in file.
	 */
	final Class<?> mainClass;

	public boolean visited;

	final File file;

	final String fileRelativePath;

	/**
	 * null value if clazz.isEnum() || clazz.isAnnotation().
	 */
	final RootOfClsMember root;

	/**
	 * .包括java文件中依次出现的成员：本地类以外的所有内部类|类中方法|注解|注释<br>
	 * 	Can't use lineNo ~> MethodGeter, because lineNo is not accurate in javassist.jar!<br>
	 * .首行日志根据行号可从中搜索到方法对象。
	 *   	
	 */
	final List<ClsMemberRange> ranges;

	public RangesOfClsMember(String relative, Class<?> clazz, File file) throws NotFoundException {
		//取得所有函数的起止下标。
		this.fileRelativePath = relative;
		this.mainClass = clazz;
		this.file = file;
		if (clazz.isEnum() || clazz.isAnnotation()) {
			Cont26.addMustBeCopiedFile(clazz);
			root = null;
			ranges = null;
			return;
		}
		String fileSt = File9.strOfFile(file);
		RootOfClsMember root = new RootOfClsMember(clazz, fileSt, true);
		if (clazz.equals(Misc9.class))//Test_match_Java8_main_____.class
			Ca.pause();
		this.root = root;
		Ca.pause();
		this.ranges = root.getClsMemberRangeList();
		Ca.pause();
	}

	public ClsRange getClsRange(Class<?> cls) {
		if (root == null)
			return null;
		ClsRange ran = root.getClsRangeMap().get(cls);
		return ran;
	}

	public MethodRange getMethodRange(Executable md) {
		if (root == null)
			return null;
		Map<Class<?>, ClsRange> map = this.root.getClsRangeMap();
		//map.keySet();
		ClsRange ran = map.get(md.getDeclaringClass());
		return ran.getMethodRange(md);
	}

	public static RangesOfClsMember getInst(int depth, Class<?> cls) {
		RangesOfClsMember ret = RangesOfClsMember.getInst00(-1, cls);
		if (ret != null)
			return ret;
		Class<?> headCls = Cont26.ClsToHeadClsMap.get(cls);
		if (headCls != null) {
			return RangesOfClsMember.getInst(-1, headCls);
		}
		return null;
	}

	private static RangesOfClsMember getInst00(int depth, Class<?> cls) {
		++depth;
		if (cls.isArray() || cls.isPrimitive() || cls.isAnnotation())
			return null;
		if (!ExtractConf.CLASS_Filter.accept(cls))
			return null;
		cls = Class9.rootClsOf(cls);
		RangesOfClsMember inst = CodeExtract.DATA_MAP.get(cls);
		if (inst != null)
			return inst;
		File file = null;
		CodeExtract.ClsPool.insertClassPath(new ClassClassPath(cls));//else javassist.NotFoundException.
		File[] roots = LogConf.getRootDirs_findFile();
		for (int i = 0; i < roots.length; i++) {
			File root = roots[i];
			file = File9.javafileOf(null, cls, roots[i]);
			if (file != null) {
				try {
					String relative = File9.relativePathOf(root, file);
					inst = new RangesOfClsMember(relative, cls, file);//<<<<<<<<<<<<<<<<<<
					if (inst.root != null) {
						Coms26.visit_all_simple_staticFinalField_fromImports_and_samePackage(inst.root);
						ClsRange cr = inst.getClsRange(cls);
						cr.setVisited();
					}
					CodeExtract.DATA_MAP.put(cls, inst);
					CodeExtract.DATA_LIST.add(inst);
					return inst;
				} catch (NotFoundException e) {
					e.printStackTrace();
					throw new RuntimeException(e);
				}
			}
		} //
		return null;
	}
	Predicate<Method> pred = null;
}
